﻿using System;
using System.Collections.Generic;
using System.Windows;
using Bookvar.ObjectModel;
using Bookvar.UI.Arrangers;

namespace Bookvar.UI.Arrangers
{
    public class TimelineTopicArranger : TopicArranger
    {
        public static readonly string TimelineStartDateKey = "TimelineStartDate";
        public static readonly string TimelineEndDateKey = "TimelineEndDate";
        private readonly List<TopicContentPresenter> sortedTopics = new List<TopicContentPresenter>();

        #region TotalHeightProperty

        private static readonly DependencyProperty TotalHeightProperty =
            DependencyProperty.Register( "TotalHeightProperty", typeof( double ), typeof( TimelineTopicArranger ) );

        public static void SetTotalHeight( DependencyObject element, double value )
        {
            element.SetValue( TotalHeightProperty, value );
        }

        public static double GetTotalHeight( DependencyObject element )
        {
            return (double) element.GetValue( TotalHeightProperty );
        }

        #endregion

        public TimelineTopicArranger( MindMapPanel panel ) : base( panel )
        {
        }

        private static double CalculateTotalHeight( TopicContentPresenter presenter )
        {
            double totalHeight = 0;
            totalHeight += presenter.DesiredSize.Height;
            foreach ( TopicContentPresenter child in presenter.Children )
            {
                totalHeight += CalculateTotalHeight( child );
            }

            SetTotalHeight( presenter, totalHeight );

            return totalHeight;
        }

        protected internal override void ArrangeMainTopic( TopicContentPresenter mainTopicPresenter, Size size )
        {
            SetLeft( mainTopicPresenter, ( size.Width - mainTopicPresenter.ActualWidth ) / 2 );
            SetTop( mainTopicPresenter, ( size.Height - mainTopicPresenter.ActualHeight ) / 2 );

            CalculateTotalHeight( mainTopicPresenter );

            sortedTopics.Clear();
            foreach ( TopicContentPresenter child in mainTopicPresenter.Children )
            {
                if ( child.Topic.CustomProperties.Contains( TimelineStartDateKey ) )
                {
                    sortedTopics.Add( child );
                }
            }
            sortedTopics.Sort( ( x, y ) => ( (DateTime) x.Topic.CustomProperties[ TimelineStartDateKey ].Value ).
                                               CompareTo( y.Topic.CustomProperties[ TimelineStartDateKey ].Value ) );
        }


        protected override void ArrangeChildTopics( TopicContentPresenter parentPresenter )
        {
            double parentLeft = GetLeft( parentPresenter );
            double parentTop = GetTop( parentPresenter );

            if ( parentPresenter.Topic is MainTopic )
            {
                DateTime previousEndDate = DateTime.MinValue;


                if ( sortedTopics.Count > 0 )
                {
                    double[] topicsX = new double[sortedTopics.Count];
                    topicsX[ 0 ] = 0;
                    SetTop( sortedTopics[ 0 ], parentTop + parentPresenter.DesiredSize.Height );
                    double childrenWidth = sortedTopics[ 0 ].DesiredSize.Width;
                    if ( sortedTopics[ 0 ].Topic.CustomProperties.Contains( TimelineEndDateKey ) )
                    {
                        previousEndDate =
                            (DateTime) sortedTopics[ 0 ].Topic.CustomProperties[ TimelineEndDateKey ].Value;
                    }

                    for ( int i = 1; i < sortedTopics.Count; i++ )
                    {
                        TopicContentPresenter child = sortedTopics[ i ];
                        double widthOffset;
                        DateTime startDate = (DateTime) child.Topic.CustomProperties[ TimelineStartDateKey ].Value;
                        DateTime endDate = DateTime.MinValue;
                        if ( child.Topic.CustomProperties.Contains( TimelineEndDateKey ) )
                        {
                            endDate = (DateTime) child.Topic.CustomProperties[ TimelineEndDateKey ].Value;
                        }
                        if ( previousEndDate > startDate )
                        {
                            DateTime previousStartDate =
                                (DateTime) sortedTopics[ i - 1 ].Topic.CustomProperties[ TimelineStartDateKey ].Value;
                            widthOffset = ( ( previousEndDate - startDate ).TotalDays /
                                            ( previousEndDate - previousStartDate ).TotalDays ) *
                                          sortedTopics[ i - 1 ].DesiredSize.Width;

                            topicsX[ i ] = childrenWidth - widthOffset;

                            widthOffset = childrenWidth - widthOffset + child.DesiredSize.Width;

                            SetTop( child, GetTop( sortedTopics[ i - 1 ] ) + sortedTopics[ i - 1 ].DesiredSize.Height );
                        }
                        else
                        {
                            
                            widthOffset = ( startDate - previousEndDate ).TotalDays;
                            topicsX[ i ] = childrenWidth + widthOffset;
                            widthOffset = child.DesiredSize.Width;
                            SetTop( child, parentTop + parentPresenter.DesiredSize.Height );
                        }

                        childrenWidth += widthOffset;
                        previousEndDate = endDate;
                    }

                    //center topics under main topic
                    double widthAddition = parentLeft - childrenWidth / 2;
                    for ( int i = 0; i < sortedTopics.Count; i++ )
                    {
                        SetLeft( sortedTopics[ i ], topicsX[ i ] + widthAddition );
                    }
                }
            }
            else
            {
                foreach ( TopicContentPresenter child in parentPresenter.Children )
                {
                    SetLeft( child, parentLeft + ( child.Topic.Depth * 10 ) );
                    SetTop( child, parentTop + parentPresenter.DesiredSize.Height );
                    parentTop += GetTotalHeight( child );
                }
            }

            base.ArrangeChildTopics( parentPresenter );
        }
    }
}